package com.china08.yxyapi.service.mg.impl;

import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.Transactional;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.math3.stat.descriptive.moment.Skewness;
import org.apache.commons.math3.stat.descriptive.moment.StandardDeviation;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFPalette;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import com.china08.yxyapi.api.manage.tec.teaching.scoreport.compareexam.CompareExamController;
import com.china08.yxyapi.api.manage.tec.teaching.scoreport.compareexam.CompareExamController.RespModel;
import com.china08.yxyapi.api.manage.tec.teaching.scoreport.compareexam.CompareExamController.StuScore;
import com.china08.yxyapi.api.manage.tec.teaching.scoreport.compareexam.CompareExamController.classScoreSk;
import com.china08.yxyapi.api.manage.tec.teaching.scoreport.createexam.ImportExamController.ExcelBackData;
import com.china08.yxyapi.api.manage.tec.teaching.scoreport.selectexam.SelectExamController;
import com.china08.yxyapi.entity.mg.scoreport.Exam;
import com.china08.yxyapi.entity.mg.scoreport.Exam.BookContent;
import com.china08.yxyapi.entity.mg.scoreport.Exam.ExamQues;
import com.china08.yxyapi.entity.mg.scoreport.Exam.Stu;
import com.china08.yxyapi.entity.mg.scoreport.ExamStudent;
import com.china08.yxyapi.entity.mg.scoreport.ExamStudent.StuQuesScore;
import com.china08.yxyapi.entity.mg.scoreport.report.ExamBaseAnalyse;
import com.china08.yxyapi.entity.mg.scoreport.report.ExamStuReport;
import com.china08.yxyapi.repository.db.YxyResBookContentsKnoledgesRepository;
import com.china08.yxyapi.repository.mg.scoreport.ExamBaseAnalyseRepository;
import com.china08.yxyapi.repository.mg.scoreport.ExamRepository;
import com.china08.yxyapi.repository.mg.scoreport.ExamStuReportRepository;
import com.china08.yxyapi.repository.mg.scoreport.ExamStudentRepository;
import com.china08.yxyapi.service.mg.ExamService;
import com.china08.yxyapi.util.DateUtils;
import com.china08.yxyapi.util.YxyResUtil;
import com.china08.yxyapi.util.algorithm.ScoreAlgorithm;
import com.china08.yxyapi.util.algorithm.regression.DataPoint;
import com.china08.yxyapi.util.algorithm.regression.RegressionLine;

import freemarker.template.Configuration;
import freemarker.template.TemplateException;

@Service
public class ExamServiceImpl implements ExamService {

    @Autowired
    private RestTemplate restTemplate;

    @Value(value = "${yx.rest.api.yx.path}")
    private String yxyApiYxUrl;

    @Autowired
    private Configuration configuration;

    @Autowired
    private MongoOperations mongoOperations;

    @Autowired
    private ExamStuReportRepository examStuReportRepository;

    @Autowired
    private ExamRepository examRepository;

    @Autowired
    private ExamStudentRepository examStudentRepository;

    @Autowired
    private ExamBaseAnalyseRepository examBaseAnalyseRepository;

    @Autowired
    private YxyResUtil yxyResUtil;

    @Autowired
    private YxyResBookContentsKnoledgesRepository yxyResBookContentsKnoledgesRepository;

    @Override
    public Page<SelectExamController.RespModel> getExamPage(String userId, String schoolId, String name, Integer status,
            String classId, Integer startDate, Integer endDate, Pageable pageable)
                    throws NumberFormatException, ParseException {

        Criteria criteria = new Criteria();

        criteria.and("teacherId").is(userId);

        criteria.and("schoolId").is(schoolId);

        // 输入框是否有值
        if (StringUtils.isNotBlank(name)) {
            String regEx = "[`~!@#$%^&*()+=|{}':;',//[//].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？]";
            Pattern p = Pattern.compile(regEx);
            Matcher m = p.matcher(name);
            name = m.replaceAll("").trim();
            criteria.andOperator(Criteria.where("name").regex(".*?" + name + ".*"));
        }

        // 班级是否选择
        if (StringUtils.isNotBlank(classId)) {
            criteria.and("classId").is(classId);
        }

        // 报告状态是否选择
        if (-1 != status) {
            criteria.and("status").is(status);
        }

        // 是否输入日期
        if (-1 != startDate && -1 != endDate) {
            criteria.and("examDate").gte(startDate).lte(endDate);
        } else if (-1 != startDate) {
            criteria.and("examDate").lte(endDate);
        } else if (-1 != endDate) {
            criteria.and("examDate").gte(startDate).lte(DateUtils.formatDate4(new Date()));
        }

        Query query = new Query();
        query.addCriteria(criteria);

        // 获取数据总数
        Long count = mongoOperations.count(query, Exam.class);

        // 获取考试成绩列表
        query.with(pageable);
        List<Exam> examLst = mongoOperations.find(query, Exam.class);

        List<SelectExamController.RespModel> respModelLst = new ArrayList<SelectExamController.RespModel>();
        for (Exam exam : examLst) {
            SelectExamController.RespModel respModel = new SelectExamController.RespModel();
            respModel.id = exam.getId();
            respModel.name = exam.getName();
            // 考试类型/科目
            respModel.type = exam.getSubjectName() + "[" + exam.getType() + "]";
            // 班级id
            respModel.classId = exam.getClassId();
            // 班级名称
            respModel.className = exam.getClassName();
            // 考试时间
            respModel.examDate = DateUtils
                    .formatDate2(DateUtils.formatStrDate4(Integer.parseInt(exam.getExamDate().toString())));
            // 状态 0--未录入数据 , 1--未发送,2--已发送
            respModel.status = exam.getStatus();
            // 感谢人集合
            respModel.thankUsers = exam.getThankUsers();
            respModelLst.add(respModel);
        }

        Page<SelectExamController.RespModel> page = new PageImpl<SelectExamController.RespModel>(respModelLst, pageable,
                count);
        return page;
    }

    /**
     * 导出成绩模板（下载模板_保存数据时触发 ）
     * 
     * @throws FileNotFoundException
     * 
     * @throws IOException
     * @throws TemplateException
     */
    @Override
    public void downloadExamExcel(HttpServletRequest request, HttpServletResponse response, List<Exam> examLst)
            throws IOException {

        // 获取流对象
        OutputStream os = response.getOutputStream();
        // zip文件输出流
        ZipOutputStream zipOutputStream = null;
        // 文件输出流转zip包文件输出流
        zipOutputStream = new ZipOutputStream(os);

        String excelName = "考试成绩模板包";
        // 获取浏览器代理
        String userAgent = request.getHeader("USER-AGENT");
        response.setContentType("application/x-download;charset=utf-8");

        if (userAgent != null) {
            userAgent = userAgent.toLowerCase();
            // 火狐浏览器，只能采用URLEncoder编码
            if (userAgent.indexOf("firefox") != -1) {
                response.setHeader("Content-Disposition",
                        "attachment;filename=" + new String((excelName + ".zip").getBytes(), "iso-8859-1"));
            } else if (userAgent.indexOf("chrome") != -1) {
                // 谷歌浏览器，编码
                response.setHeader("Content-Disposition",
                        "attachment;filename=" + new String((excelName + ".zip").getBytes(), "iso-8859-1"));
            } else {
                // IE+浏览器
                response.setHeader("Content-Disposition",
                        "attachment;filename=" + URLEncoder.encode(excelName + ".zip", "utf-8"));
            }
        }

        for (Exam exam : examLst) {
            // 小题数据list
            List<ExamQues> quesLst = new ArrayList<ExamQues>();
            // 标题名
            String titleName = null;
            // 考试编号
            String examId = null;
            // 班级名称
            String className = null;

            if (exam.getQuestions() != null) {
                quesLst.addAll(exam.getQuestions());
            }
            titleName = exam.getName();
            examId = exam.getExamId();
            className = exam.getClassName();

            // 模板文件
            URL url = ExamServiceImpl.class.getClassLoader().getResource("META-INF/template/temp.xls");
            URLConnection uc = url.openConnection();
            InputStream in = uc.getInputStream();
            HSSFWorkbook workBook = new HSSFWorkbook(in);

            HSSFSheet sheet = workBook.getSheetAt(0);

            CellStyle cellStyle = workBook.createCellStyle();
            // 自定义取色
            HSSFPalette customPalette = workBook.getCustomPalette();
            customPalette.setColorAtIndex(HSSFColor.ROYAL_BLUE.index, (byte) 47, (byte) 117, (byte) 181);
            // 背景颜色
            cellStyle.setFillForegroundColor(HSSFColor.ROYAL_BLUE.index);
            cellStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);
            cellStyle.setBorderBottom(CellStyle.BORDER_THIN); // 下边框
            cellStyle.setBorderLeft(CellStyle.BORDER_THIN);// 左边框
            cellStyle.setBorderTop(CellStyle.BORDER_THIN);// 上边框
            cellStyle.setBorderRight(CellStyle.BORDER_THIN);// 右边框
            cellStyle.setBottomBorderColor(HSSFColor.GREY_50_PERCENT.index);// 边框颜色下
            cellStyle.setLeftBorderColor(HSSFColor.GREY_50_PERCENT.index);// 边框颜色左
            cellStyle.setTopBorderColor(HSSFColor.GREY_50_PERCENT.index);// 边框颜色上
            cellStyle.setRightBorderColor(HSSFColor.GREY_50_PERCENT.index);// 边框颜色右
            cellStyle.setAlignment(CellStyle.ALIGN_CENTER);// 水平居中
            cellStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER);// 垂直居中

            Font font = workBook.createFont();
            font.setColor(HSSFColor.WHITE.index);// HSSFColor.VIOLET.index
            font.setFontHeightInPoints((short) 11);// 字体颜色
            cellStyle.setFont(font);

            // 修改考试模板名称
            sheet.getRow(0).getCell(0).setCellValue("EXCEL模板 " + titleName);
            // 修改考试编号
            sheet.getRow(1).getCell(1).setCellValue(examId);
            // 内置：信息班级id
            sheet.getRow(1).getCell(3).setCellValue(exam.getClassId());
            // 试卷满分数据
            sheet.getRow(3).getCell(6).setCellValue(exam.getTotalScore() + "分制");

            // 小题排序
            quesLst.sort(new Comparator<ExamQues>() {
                @Override
                public int compare(ExamQues o1, ExamQues o2) {
                    if (o1.section == o2.section) {
                        if (o1.no > o2.no) { //
                            return 1;
                        } else {
                            return -1;
                        }
                    } else if (o1.section > o2.section) { //
                        return 1;
                    } else {
                        return -1;
                    }
                }
            });

            // 小题数据Excel使用
            List<Map<String, Object>> quesMapLst = new ArrayList<Map<String, Object>>();
            for (ExamQues ques : quesLst) {
                Map<String, Object> quesMap = new HashMap<String, Object>();
                if (ques.order_num != 0) {
                    if (ques.no != 0) {
                        quesMap.put("title", ques.sectionName + "_" + ques.noName);
                    } else {
                        quesMap.put("title", ques.sectionName);
                    }
                    quesMap.put("score", ques.score);
                    quesMapLst.add(quesMap);
                }
            }

            // 试卷数据标题：合并单元格显示
            CellRangeAddress cra = new CellRangeAddress(1, 1, 6, 6 + quesLst.size());
            sheet.addMergedRegion(cra);
            sheet.getRow(cra.getFirstRow()).getCell(cra.getFirstColumn()).setCellValue("试卷数据");

            // 小题显示
            for (int i = 0; i < quesMapLst.size(); i++) {
                HSSFCell xc0 = sheet.getRow(0).createCell(7 + i);
                xc0.setCellStyle(cellStyle);
                sheet.setColumnWidth(7 + i, 7680);
                // 标题显示
                HSSFCell xc1 = sheet.getRow(2).createCell(7 + i);
                xc1.setCellValue(quesMapLst.get(i).get("title").toString());
                xc1.setCellStyle(cellStyle);
                // 分数显示
                HSSFCell xc2 = sheet.getRow(3).createCell(7 + i);
                xc2.setCellValue(Integer.valueOf(quesMapLst.get(i).get("score").toString()));
                xc2.setCellStyle(cellStyle);
            }

            int index = 4;

            List<Stu> stuLst = new ArrayList<Exam.Stu>();
            stuLst.addAll(exam.getStudents());
            boolean nullFlag = true;
            for (Stu stu : exam.getStudents()) {
                if (!StringUtils.isNoneBlank(stu.student_no)) {
                    nullFlag = false;
                    break;
                }
            }
            if (nullFlag) {
                stuLst.sort(new Comparator<Stu>() {
                    @Override
                    public int compare(Stu s1, Stu s2) {
                        return new Long(s1.student_no) > new Long(s2.student_no) ? 1 : -1;
                    }
                });
            }

            for (Stu stu : stuLst) {
                HSSFRow newRow = sheet.createRow(index);
                newRow.setHeightInPoints(25);
                // 年级
                HSSFCell xc0 = newRow.createCell(0);
                xc0.setCellValue(stu.grade_name + "");
                xc0.setCellStyle(cellStyle);
                // 班级名称
                HSSFCell xc1 = newRow.createCell(1);
                xc1.setCellValue(className + "");
                xc1.setCellStyle(cellStyle);
                // 学号
                HSSFCell xc2 = newRow.createCell(2);
                xc2.setCellValue(stu.student_no + "");
                xc2.setCellStyle(cellStyle);
                // 班级id
                HSSFCell xc3 = newRow.createCell(3);
                xc3.setCellValue(exam.getClassId() + "");
                xc3.setCellStyle(cellStyle);
                // 姓名
                HSSFCell xc4 = newRow.createCell(4);
                xc4.setCellValue(stu.student_name + "");
                xc4.setCellStyle(cellStyle);
                // 编号
                HSSFCell xc5 = newRow.createCell(5);
                xc5.setCellValue(stu.student_id + "");
                xc5.setCellStyle(cellStyle);
                index++;
            }

            // 创建压缩格式的内文件 并放在压缩文件中
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            // 将数据写入到模板中
            workBook.write(baos);

            ZipEntry zipEntry = new ZipEntry(titleName + "/" + titleName + "_" + className + ".xls");
            zipOutputStream.putNextEntry(zipEntry);
            // 读取待压缩的文件并写进压缩包里
            zipOutputStream.write(baos.toByteArray());
        }

        zipOutputStream.close();
        os.close();
    }

    /**
     * 解析Excel 并返回状态信息
     * 
     * @param wb
     * @param backData
     * @return
     */
    @Override
    public ExcelBackData parsingExcel(Workbook wb, ExcelBackData backData, String uploadUserId) {
        List<ExamStudent> examStuLst = new ArrayList<ExamStudent>();

        Sheet sheet = wb.getSheetAt(0);
        // 行数
        int rowNum = 0;
        // 是否存在小题
        boolean isQues = false;
        // 小题最后列数
        int quesNum = 0;
        // 考试信息
        Exam exam = null;
        // 小题信息
        List<ExamQues> examQuesLst = null;
        // 学生列表
        Map<String, Map<String, Object>> studentIdLst = new HashMap<String, Map<String, Object>>();
        // 班级列表
        String classLst = null;

        if (sheet.getLastRowNum() < 4 && sheet.getPhysicalNumberOfRows() == 0) {
            backData.errorFlag = false;
            backData.errorMsg = "该Excel无考试数据，请重新下载，录入数据并上传";
            return backData;
        }

        for (Row row : sheet) {
            rowNum = row.getRowNum();
            if (0 == rowNum) {
                continue;
            }
            if (1 == rowNum) {
                String valueStr = getCellValueAsString(row.getCell(1));
                if (valueStr == null) {
                    backData.errorFlag = false;
                    backData.errorMsg = "该Excel试卷编号不存在，请重新下载，录入数据并上传";
                    return backData;
                }
                String valueStr2 = getCellValueAsString(row.getCell(3));
                if (valueStr2 == null) {
                    backData.errorFlag = false;
                    backData.errorMsg = "该Excel试卷对应班级列表不存在，请重新下载，录入数据并上传";
                    return backData;
                }
                classLst = valueStr2;

                exam = examRepository.findByExamIdAndClassId(valueStr, classLst);
                // 判断该考试是否存在
                if (null == exam) {
                    backData.errorFlag = false;
                    backData.errorMsg = "该Excel考试数据不存在，请重新下载，录入数据并上传";
                    return backData;
                }

                // 上传人是否为考试创建人
                if (!uploadUserId.equals(exam.getTeacherId())) {
                    backData.errorFlag = false;
                    backData.errorMsg = "该Excel上传人与创建考试老师账户不符，请您上传您所创建的考试成绩";
                    return backData;
                }

                // 判断该模板是否存在小题数据
                examQuesLst = exam.getQuestions();
                if (examQuesLst.size() > 0) {
                    isQues = true;
                    quesNum = 6 + examQuesLst.size();
                    // 小题排序
                    examQuesLst.sort(new Comparator<ExamQues>() {

                        @Override
                        public int compare(ExamQues o1, ExamQues o2) {
                            if (o1.section == o2.section) {
                                if (o1.no > o2.no) { //
                                    return 1;
                                } else {
                                    return -1;
                                }
                            } else if (o1.section > o2.section) { //
                                return 1;
                            } else {
                                return -1;
                            }
                        }
                    });
                }
                // 获取学生列表
                for (Stu stu : exam.getStudents()) {
                    Map<String, Object> stuMap = new HashMap<String, Object>();
                    stuMap.put("name", stu.student_name);
                    stuMap.put("no", stu.student_no);
                    stuMap.put("grade", stu.grade_name);
                    stuMap.put("className", exam.getClassName());
                    stuMap.put("classId", exam.getClassId());
                    stuMap.put("exam", exam);
                    studentIdLst.put(stu.student_id, stuMap);
                }
            }

            // 分数分制
            if (rowNum == 3) {
                // 满分分制判断
                String fullPointStr = getCellValueAsString(row.getCell(6));
                if (!fullPointStr.equals(exam.getTotalScore() + "分制")) {
                    backData.errorFlag = false;
                    backData.errorMsg = "该Excel满分分制与所创建的考试满分信息不一致，请检查或重新下载，录入数据并上传";
                    return backData;
                }
                // 小题分数分制
                if (isQues) {
                    for (int i = 7; i <= quesNum; i++) {
                        String quesStr = getCellValueAsString(row.getCell(i));
                        if (!quesStr.equals(examQuesLst.get(i - 7).score + "")) {
                            backData.errorFlag = false;
                            backData.errorMsg = "该Excel小题分制与所创建的考试小题分制信息不一致，错误位置：第" + (row.getRowNum() + 1) + "行，第"
                                    + (i - 1) + "列，请检查或重新下载，后重新录入数据并上传";
                            return backData;
                        }
                    }
                }
            }

            if (rowNum > 3) {
                String grade = getCellValueAsString(row.getCell(0));
                if (null == getCellValueAsString(row.getCell(0))) {
                    break;
                }
                // 获取Excel数据
                String classNick = row.getCell(1).toString();
                String stuNo = row.getCell(2).toString();
                String classId = getCellValueAsString(row.getCell(3));
                String stuName = row.getCell(4).toString();
                String stuId = getCellValueAsString(row.getCell(5));
                String score = getCellValueAsString(row.getCell(6));

                // 基本信息
                if (null == classNick || null == stuNo || null == classId || null == stuName || null == stuId) {
                    backData.errorFlag = false;
                    backData.errorMsg = "该Excel学生基本信息不存在，请重新下载，录入数据并上传";
                    return backData;
                }

                // stuId
                if (null == studentIdLst.get(stuId)) {
                    backData.errorFlag = false;
                    backData.errorMsg = "该Excel内置信息不对应，请重新下载，录入数据并上传";
                    return backData;
                }
                // 年级名称
                if (!grade.equals(studentIdLst.get(stuId).get("grade"))) {
                    backData.errorFlag = false;
                    backData.errorMsg = "该Excel年级名称信息错误，错误位置：第" + (row.getRowNum() + 1) + "行，第" + 1 + "列，请检查后重新录入数据并上传";
                    return backData;
                }
                // 班级名称
                if (!classNick.equals(studentIdLst.get(stuId).get("className"))) {
                    backData.errorFlag = false;
                    backData.errorMsg = "该Excel班级名称信息错误，错误位置：第" + (row.getRowNum() + 1) + "行，第" + 2 + "列，请检查后重新录入数据并上传";
                    return backData;
                }
                // 学生学号
                if (!stuNo.equals(studentIdLst.get(stuId).get("no"))) {
                    backData.errorFlag = false;
                    backData.errorMsg = "该Excel学生学号信息错误，错误位置：第" + (row.getRowNum() + 1) + "行，第" + 3 + "列，请检查后重新录入数据并上传";
                    return backData;
                }
                // 班级Id
                if (!classId.equals(studentIdLst.get(stuId).get("classId"))) {
                    backData.errorFlag = false;
                    backData.errorMsg = "该Excel内置信息不对应，请重新下载，录入数据并上传";
                    return backData;
                }
                // 学生姓名
                if (!stuName.equals(studentIdLst.get(stuId).get("name"))) {
                    backData.errorFlag = false;
                    backData.errorMsg = "该Excel学生姓名错误，错误位置：第" + (row.getRowNum() + 1) + "行，第" + 4 + "列，请检查后重新录入数据并上传";
                    return backData;
                }

                // 分数数据
                if (!isNumericDouble(score)) {
                    if (score.equals("/")) {
                        studentIdLst.remove(stuId);
                        continue;
                    }
                    backData.errorFlag = false;
                    backData.errorMsg = "该Excel数据类型不正确或无数据，错误位置：第" + (row.getRowNum() + 1) + "行，第" + 5
                            + "列，请检查后重新录入数据并上传";
                    return backData;
                }

                // 是否符合分数要求
                if (Double.valueOf(score) < 0 || Double.valueOf(score) > exam.getTotalScore()) {
                    backData.errorFlag = false;
                    backData.errorMsg = "该Excel数据大于分数制度或小于0，错误位置：第" + (row.getRowNum() + 1) + "行，第" + 5
                            + "列，请检查后重新录入数据并上传";
                    return backData;
                }

                ExamStudent examStu = new ExamStudent();
                List<StuQuesScore> stuQuesLst = new ArrayList<StuQuesScore>();

                // 若有小题 获取小题信息
                if (isQues) {
                    // 小题总分
                    double getQuesScore = 0d;
                    for (int i = 7; i <= quesNum; i++) {
                        String valueStr = getCellValueAsString(row.getCell(i));
                        if (null == valueStr && score == null) {
                            backData.errorFlag = false;
                            backData.errorMsg = "该Excel小题数据未录入，请录入数据并上传";
                            return backData;
                        }
                        if (!isNumericDouble(valueStr)) {
                            backData.errorFlag = false;
                            backData.errorMsg = "该Excel数据类型不正确，错误位置：第" + (row.getRowNum() + 1) + "行，第" + (i - 1)
                                    + "列，请检查后重新录入数据并上传";
                            return backData;
                        }

                        // 是否符合分数要求
                        if (Double.valueOf(valueStr) < 0 || Double.valueOf(valueStr) > examQuesLst.get(i - 7).score) {
                            backData.errorFlag = false;
                            backData.errorMsg = "该Excel数据大于分数制度或小于0，错误位置：第" + (row.getRowNum() + 1) + "行，第" + 5
                                    + "列，请检查后重新录入数据并上传";
                            return backData;
                        }

                        StuQuesScore stuQues = examStu.new StuQuesScore();
                        stuQues.section = examQuesLst.get(i - 7).section;// 大题号
                        stuQues.no = examQuesLst.get(i - 7).no;// 小题号
                        stuQues.order_num = examQuesLst.get(i - 7).order_num;// 序列号
                        stuQues.score = examQuesLst.get(i - 7).score;// 分数
                        if (score != null) {
                            // 学生本题的分数
                            stuQues.stu_score = Double.valueOf(valueStr);
                        } else {
                            stuQues.stu_score = -1d;
                        }
                        stuQuesLst.add(stuQues);
                        getQuesScore += Double.valueOf(valueStr);
                    }
                    if (getQuesScore != Double.valueOf(score)) {
                        backData.errorFlag = false;
                        backData.errorMsg = "该Excel数据总分与小题分相加后比较不一致，请检查后重新录入数据并上传，错误位置：第" + (row.getRowNum() + 1) + "行";
                        return backData;
                    }
                    examStu.setStuQuesScores(stuQuesLst);
                }

                examStu.setExam((Exam) studentIdLst.get(stuId).get("exam"));
                examStu.setStudentId(stuId);
                examStu.setStudentNick(stuName);
                examStu.setClassId(classId);
                examStu.setClassName(classNick);
                examStu.setStuTotalScore(score == null ? -1 : Double.valueOf(score));
                examStuLst.add(examStu);
                studentIdLst.remove(stuId);
            }
        }

        if (studentIdLst.size() > 0) {
            List<String> nameLst = new ArrayList<>();
            for (Entry<String, Map<String, Object>> stu : studentIdLst.entrySet()) {
                nameLst.add(stu.getValue().get("name").toString());
            }
            backData.errorFlag = false;
            backData.errorMsg = "该Excel基本数据错误，缺少" + StringUtils.join(nameLst, ",") + "同学的数据，请检查后重新录入数据并上传";
            return backData;
        }

        backData.errorFlag = true;
        backData.errorMsg = "";
        backData.examStuLst = examStuLst;
        backData.examId = exam.getId();
        return backData;
    }

    /**
     * 考试成绩年级比较
     * 
     * @param idLst
     * @param id
     * @return
     */
    @Override
    public CompareExamController.RespModel compareExam(List<String> idLst, String id) {
        CompareExamController.RespModel respModel = new RespModel();

        List<Exam> examLst = new ArrayList<>();
        examLst = examRepository.findByIdIn(idLst);
        Exam exam = examRepository.findOne(id);
        if (0 != examLst.size()) {
            // 试卷满分
            int examTotalScore = exam.getTotalScore();
            // 加入本次考试成绩对象
            examLst.add(exam);
            // 进行对比的所有成绩
            List<ExamStudent> examStuLst = new ArrayList<>();
            examStuLst = examStudentRepository.findByExamIn(examLst);
            // 进行对比的本班成绩
            List<ExamStudent> examStuBenLst = new ArrayList<>();
            examStuBenLst = examStudentRepository.findByExam(exam);

            // 所选班级的成绩列表
            List<Double> scoreAllLst = new ArrayList<Double>();
            for (ExamStudent es : examStuLst) {
                scoreAllLst.add(es.getStuTotalScore());
            }

            // 学生成绩列表排序 学生在所有数据排名
            examStuLst.sort((ExamStudent h1, ExamStudent h2) -> h2.getStuTotalScore().compareTo(h1.getStuTotalScore()));

            List<String> examStuBen = examStuBenLst.stream().map(x -> x.getStudentId()).collect(Collectors.toList());

            List<StuScore> StuScoreLst = new ArrayList<>();
            for (int i = 0; i < examStuLst.size(); i++) {
                if (examStuBen.contains(examStuLst.get(i).getStudentId())) {
                    StuScore stuScore = new StuScore();
                    stuScore.stuId = examStuLst.get(i).getStudentId();
                    stuScore.stuName = examStuLst.get(i).getStudentNick();
                    stuScore.score = examStuLst.get(i).getStuTotalScore();
                    stuScore.index = i + 1;
                    StuScoreLst.add(stuScore);
                }
            }
            respModel.StuScoreLst = StuScoreLst;

            // 试卷难度是否使用sk进行计算
            boolean noSk = true;
            // 班级难度排序
            List<classScoreSk> classSkLst = new ArrayList<>();
            for (Exam examForSk : examLst) {
                // List<ExamStudent> examStuForSkLst = new ArrayList<>();
                // examStuForSkLst =
                // examStudentRepository.findByExam(examForSk);
                // Skewness skewness = new Skewness();
                // int size = examStuForSkLst.size();
                // double[] arr = new double[size];
                // for (int i = 0; i < examStuForSkLst.size(); i++) {
                // arr[i] = examStuForSkLst.get(i).getStuTotalScore();
                // }
                // double getSk = skewness.evaluate(arr);

                List<ExamStudent> examStuForSkLst = new ArrayList<>();
                examStuForSkLst = examStudentRepository.findByExam(examForSk);

                double heStuTotalScore = 0d, getSk = 0d;
                for (int i = 0; i < examStuForSkLst.size(); i++) {
                    heStuTotalScore += examStuForSkLst.get(i).getStuTotalScore();
                }
                if (examStuForSkLst.size() != 0) {
                    getSk = heStuTotalScore / examStuForSkLst.size();
                }

                classScoreSk scoreSk = new classScoreSk();
                scoreSk.className = examForSk.getClassName();
                scoreSk.skValue = getSk;
                classSkLst.add(scoreSk);
                // 是否存在小题
                if (0 == examForSk.getQuestions().size()) {
                    noSk = false;
                }
            }
            classSkLst.sort((classScoreSk h1, classScoreSk h2) -> h2.skValue.compareTo(h1.skValue));
            respModel.classSkLst = classSkLst;

            if (noSk) {
                // 进行小题难度计算
                // 拥有小题时
                int quesNum = exam.getQuestions().size();
                List<Double> itemDifficultyLst = new ArrayList<Double>();
                List<Double> fullMarksLst = new ArrayList<Double>();
                for (int i = 1; i <= quesNum; i++) {
                    List<Double> quesLst = new ArrayList<Double>();
                    int fullScore = 0;
                    for (ExamStudent examStudent : examStuLst) {
                        for (StuQuesScore stuQues : examStudent.getStuQuesScores()) {
                            if (stuQues.order_num == i) {
                                quesLst.add(stuQues.stu_score);
                                fullScore = stuQues.score;
                                break;
                            }
                        }
                    }
                    fullMarksLst.add((double) fullScore);
                    itemDifficultyLst.add(ScoreAlgorithm.itemDifficulty(quesLst, fullScore));
                }
                // 难度系数
                double d = ScoreAlgorithm.testDifficulty(itemDifficultyLst, fullMarksLst);
                if (d >= 0.7) {
                    respModel.difficultValue = "易";
                } else if (d >= 0.4 && d < 0.7) {
                    respModel.difficultValue = "一般";
                } else if (d >= 0.1 && d < 0.4) {
                    respModel.difficultValue = "难";
                } else if (d < 0.1) {
                    respModel.difficultValue = "非常难";
                }
            } else {
                // 进行整体sk值计算
                Skewness skewness = new Skewness();
                int size = scoreAllLst.size();
                double[] arr = new double[size];
                for (int i = 0; i < scoreAllLst.size(); i++) {
                    arr[i] = scoreAllLst.get(i);
                }
                double getSk = skewness.evaluate(arr);
                double avgScore = ScoreAlgorithm.scoreAvg(scoreAllLst);
                if (getSk > 0) {
                    if (avgScore >= examTotalScore * 0.9) {// 优秀：易
                        respModel.difficultValue = "易";
                    } else if (avgScore >= examTotalScore * 0.6 && avgScore < examTotalScore * 0.9) {// 良好、及格：一般
                        respModel.difficultValue = "一般";
                    } else if (avgScore >= examTotalScore * 0.45 && avgScore < examTotalScore * 0.6) {// 不及格：难
                        respModel.difficultValue = "难";
                    } else if (avgScore < examTotalScore * 0.45) {// 过差：非常难
                        respModel.difficultValue = "非常难";
                    }
                } else if (getSk == 0) {
                    if (avgScore >= examTotalScore * 0.6) {// 优秀、良好、及格：一般
                        respModel.difficultValue = "一般";
                    } else if (avgScore < examTotalScore * 0.6) {// 不及格、过差：难
                        respModel.difficultValue = "难";
                    }
                } else if (getSk < 0) {
                    if (avgScore >= examTotalScore * 0.8) {// 优秀、良好：一般
                        respModel.difficultValue = "一般";
                    } else if (avgScore >= examTotalScore * 0.6 && avgScore < examTotalScore * 0.8) {// 及格：难
                        respModel.difficultValue = "难";
                    } else if (avgScore < examTotalScore * 0.6) {// 不及格、过差：非常难
                        respModel.difficultValue = "非常难";
                    }
                }
            }

            // 分布分析
            String rankRemark = "";
            // 人数范围所需成绩集合（移除记录使用）
            List<Double> hsLst = new ArrayList<>();
            hsLst.addAll(scoreAllLst);
            // 迭代基数数字
            int baseNum = 0;
            switch (examTotalScore) {
            case 100:
                baseNum = 10;
                break;
            case 120:
                baseNum = 12;
                break;
            case 150:
                baseNum = 15;
                break;
            case 180:
                baseNum = 18;
                break;
            }
            Map<String, Integer> histogramMap = new HashMap<String, Integer>();
            // 循环取出范围
            for (int i = 0; i <= examTotalScore - baseNum; i += baseNum) {
                int count = 0;
                for (int j = 0; j < hsLst.size(); j++) {
                    if (i == 0) {
                        if (i <= hsLst.get(j) && hsLst.get(j) < (i + baseNum)) {
                            count++;
                        }
                    } else if (i == examTotalScore - baseNum) {
                        if (i <= hsLst.get(j) && hsLst.get(j) <= (i + baseNum)) {
                            count++;
                        }
                    } else {
                        if (i <= hsLst.get(j) && hsLst.get(j) < (i + baseNum)) {
                            count++;
                        }
                    }
                }
                histogramMap.put((i + baseNum) + "", count);
            }
            // 年级数据各个分数段
            List<Map.Entry<String, Integer>> histogramMapLst = new ArrayList<Map.Entry<String, Integer>>(
                    histogramMap.entrySet());
            // 人数排序
            histogramMapLst.sort((Map.Entry<String, Integer> h1, Map.Entry<String, Integer> h2) -> h2.getValue()
                    .compareTo(h1.getValue()));
            // 本班的柱状分布图
            ExamBaseAnalyse examAnalyse = examBaseAnalyseRepository.findByExam(exam);
            List<Map.Entry<String, Integer>> histogramBenMapLst = new ArrayList<Map.Entry<String, Integer>>(
                    examAnalyse.getHistogram().entrySet());
            // 本班人数排序
            histogramBenMapLst.sort((Map.Entry<String, Integer> h1, Map.Entry<String, Integer> h2) -> h2.getValue()
                    .compareTo(h1.getValue()));
            int histogramFlag = histogramBenMapLst.get(0).getKey().compareTo(histogramMapLst.get(0).getKey());
            int keyStr = Integer.parseInt(histogramBenMapLst.get(0).getKey());
            // 成绩分布
            if (histogramFlag > 0) {
                rankRemark += "如图，在本次考试中，当前班级成绩主要集中在" + (keyStr - 10) + "~" + keyStr + "分之间，高于年级成绩主要集中分段。";
            } else if (histogramFlag == 0) {
                rankRemark += "如图，在本次考试中，当前班级成绩主要集中在" + (keyStr - 10) + "~" + keyStr + "分之间，符合年级成绩主要集中分段。";
            } else if (histogramFlag < 0) {
                rankRemark += "如图，在本次考试中，当前班级成绩主要集中在" + (keyStr - 10) + "~" + keyStr + "分之间，低于年级成绩主要集中分段。";
            }

            double hiScoreBen = 0, hiScoreSum = 0, liScoreBen = 0, liScoreSum = 0;
            for (Entry<String, Integer> entry : histogramBenMapLst) {
                if (Integer.parseInt(entry.getKey()) >= (examTotalScore)) {
                    hiScoreBen += entry.getValue();
                }
                if (Integer.parseInt(entry.getKey()) < (examTotalScore * 0.7)) {
                    liScoreBen += entry.getValue();
                }
            }
            for (Entry<String, Integer> entry : histogramMapLst) {
                if (Integer.parseInt(entry.getKey()) >= (examTotalScore)) {
                    hiScoreSum += entry.getValue();
                }
                if (Integer.parseInt(entry.getKey()) < (examTotalScore * 0.7)) {
                    liScoreSum += entry.getValue();
                }
            }
            // 高分占比
            double hiScoreAvg = hiScoreSum == 0d ? 0d : hiScoreBen / hiScoreSum;
            if (hiScoreAvg >= 0.6) {
                rankRemark += "并且高分占年级比重较高。";
            } else if (hiScoreAvg >= 0.2 && hiScoreAvg < 0.6) {
                rankRemark += "但班级高分占年级比重一般。";
            } else if (hiScoreAvg < 0.2) {
                rankRemark += "但高分占比较低。";
            }
            // 低分占比
            double liScoreAvg = liScoreSum == 0d ? 0d : liScoreBen / liScoreSum;
            if (liScoreAvg >= 0.6) {
                rankRemark += "同时低分占比过大，请加强当前班级基础巩固。";
            } else if (liScoreAvg < 0.4) {
                rankRemark += "同时低分成绩占比小于40%，希望老师进行针对性教学。";
            }
            // 平均成绩
            List<ExamBaseAnalyse> examAnalyseLst = examBaseAnalyseRepository.findByExamIn(examLst);
            examAnalyseLst.sort((ExamBaseAnalyse h1, ExamBaseAnalyse h2) -> h2.getAverage().compareTo(h1.getAverage()));
            for (int i = 0; i < examAnalyseLst.size(); i++) {
                if (examAnalyseLst.get(i).getId().equals(examAnalyse.getId())) {
                    if (0 == i) {
                        rankRemark += "成绩平均分最高，请保持班级学习成绩";
                    } else {
                        List<String> classNameStr = new ArrayList<>();
                        for (int j = 0; j < i; j++) {
                            Exam exam2 = examRepository.findOne(examAnalyseLst.get(j).getExam().getId());
                            classNameStr.add(exam2.getClassName());
                        }
                        rankRemark += "成绩平均分低于" + StringUtils.join(classNameStr.toArray(), ",") + "，请注重教学法的调整。";
                    }
                    break;
                }
            }
            respModel.rankRemark = rankRemark;

            // 分布分析
            List<Double> scoreBenLst = new ArrayList<Double>();
            for (ExamStudent es : examStuBenLst) {
                scoreBenLst.add(es.getStuTotalScore());
            }
            // 本班级各个阶段分数
            double[] fenbuBenLst = new double[] { 0, 0, 0, 0, 0 };
            // 全部班级各个阶段分数
            double[] fenbuAllLst = new double[] { 0, 0, 0, 0, 0 };
            for (double ben : scoreBenLst) {
                if (ben >= examTotalScore * 0.9) {// 优秀
                    fenbuBenLst[0] += 1;
                } else if (ben >= examTotalScore * 0.8 && ben < examTotalScore * 0.9) {// 良好
                    fenbuBenLst[1] += 1;
                } else if (ben >= examTotalScore * 0.6 && ben < examTotalScore * 0.8) {// 及格
                    fenbuBenLst[2] += 1;
                } else if (ben < examTotalScore * 0.6) {// 不及格
                    fenbuBenLst[3] += 1;
                    if (ben < examTotalScore * 0.45) {// 过差
                        fenbuBenLst[4] += 1;
                    }
                }
            }
            for (double all : scoreAllLst) {
                if (all >= examTotalScore * 0.9) {// 优秀
                    fenbuAllLst[0] += 1;
                } else if (all >= examTotalScore * 0.8 && all < examTotalScore * 0.9) {// 良好
                    fenbuAllLst[1] += 1;
                } else if (all >= examTotalScore * 0.6 && all < examTotalScore * 0.8) {// 及格
                    fenbuAllLst[2] += 1;
                } else if (all < examTotalScore * 0.6) {// 不及格
                    fenbuAllLst[3] += 1;
                    if (all < examTotalScore * 0.45) {// 过差
                        fenbuAllLst[4] += 1;
                    }
                }
            }
            // 优良雷达图
            Map<Integer, Double> fineRank = new HashMap<Integer, Double>();
            BigDecimal bd = null;
            for (int i = 0; i < 5; i++) {
                double rank = fenbuAllLst[i] == 0d ? 0d : fenbuBenLst[i] / fenbuAllLst[i] * 100;
                bd = new BigDecimal(rank);
                fineRank.put(i, bd.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
            }
            respModel.fineRank = fineRank;
        } else {
            // 试卷满分
            int examTotalScore = exam.getTotalScore();
            // 加入本次考试成绩对象
            examLst.add(exam);
            // 进行对比的所有成绩
            List<ExamStudent> examStuLst = new ArrayList<>();
            examStuLst = examStudentRepository.findByExam(exam);

            // 所选班级的成绩列表
            List<Double> scoreAllLst = new ArrayList<Double>();
            for (ExamStudent es : examStuLst) {
                scoreAllLst.add(es.getStuTotalScore());
            }

            // 学生成绩列表排序 学生在所有数据排名
            examStuLst.sort((ExamStudent h1, ExamStudent h2) -> h2.getStuTotalScore().compareTo(h1.getStuTotalScore()));

            List<StuScore> StuScoreLst = new ArrayList<>();
            for (int i = 0; i < examStuLst.size(); i++) {
                StuScore stuScore = new StuScore();
                stuScore.stuId = examStuLst.get(i).getStudentId();
                stuScore.stuName = examStuLst.get(i).getStudentNick();
                stuScore.score = examStuLst.get(i).getStuTotalScore();
                stuScore.index = i + 1;
                StuScoreLst.add(stuScore);
            }
            respModel.StuScoreLst = StuScoreLst;

            // 试卷难度是否使用sk进行计算
            boolean noSk = true;
            // 班级难度排序
            List<classScoreSk> classSkLst = new ArrayList<>();

            Skewness skewness = new Skewness();
            int size = examStuLst.size();
            double[] arr = new double[size];
            for (int i = 0; i < examStuLst.size(); i++) {
                arr[i] = examStuLst.get(i).getStuTotalScore();
            }
            double getSk = skewness.evaluate(arr);
            classScoreSk scoreSk = new classScoreSk();
            scoreSk.className = exam.getClassName();
            scoreSk.skValue = getSk;
            classSkLst.add(scoreSk);
            // 是否存在小题
            if (0 == exam.getQuestions().size()) {
                noSk = false;
            }
            respModel.classSkLst = classSkLst;

            if (noSk) {
                // 进行小题难度计算
                // 拥有小题时
                int quesNum = exam.getQuestions().size();
                List<Double> itemDifficultyLst = new ArrayList<Double>();
                List<Double> fullMarksLst = new ArrayList<Double>();
                // 学生成绩是否包含小题
                boolean quesIsNot = false;
                for (int i = 1; i <= quesNum; i++) {
                    List<Double> quesLst = new ArrayList<Double>();
                    int fullScore = 0;
                    for (ExamStudent examStudent : examStuLst) {
                        if (null == examStudent.getStuQuesScores()) {
                            quesIsNot = true;
                            break;
                        }
                        for (StuQuesScore stuQues : examStudent.getStuQuesScores()) {
                            if (stuQues.order_num == i) {
                                quesLst.add(stuQues.stu_score);
                                fullScore = stuQues.score;
                                break;
                            }
                        }
                    }
                    if (quesIsNot) {
                        break;
                    }
                    fullMarksLst.add((double) fullScore);
                    itemDifficultyLst.add(ScoreAlgorithm.itemDifficulty(quesLst, fullScore));
                }
                if (quesIsNot) {
                    double avgScore = ScoreAlgorithm.scoreAvg(scoreAllLst);
                    if (getSk > 0) {
                        if (avgScore >= examTotalScore * 0.9) {// 优秀：易
                            respModel.difficultValue = "易";
                        } else if (avgScore >= examTotalScore * 0.6 && avgScore < examTotalScore * 0.9) {// 良好、及格：一般
                            respModel.difficultValue = "一般";
                        } else if (avgScore >= examTotalScore * 0.45 && avgScore < examTotalScore * 0.6) {// 不及格：难
                            respModel.difficultValue = "难";
                        } else if (avgScore < examTotalScore * 0.45) {// 过差：非常难
                            respModel.difficultValue = "非常难";
                        }
                    } else if (getSk == 0) {
                        if (avgScore >= examTotalScore * 0.6) {// 优秀、良好、及格：一般
                            respModel.difficultValue = "一般";
                        } else if (avgScore < examTotalScore * 0.6) {// 不及格、过差：难
                            respModel.difficultValue = "难";
                        }
                    } else if (getSk < 0) {
                        if (avgScore >= examTotalScore * 0.8) {// 优秀、良好：一般
                            respModel.difficultValue = "一般";
                        } else if (avgScore >= examTotalScore * 0.6 && avgScore < examTotalScore * 0.8) {// 及格：难
                            respModel.difficultValue = "难";
                        } else if (avgScore < examTotalScore * 0.6) {// 不及格、过差：非常难
                            respModel.difficultValue = "非常难";
                        }
                    }
                } else {
                    // 难度系数
                    double d = ScoreAlgorithm.testDifficulty(itemDifficultyLst, fullMarksLst);
                    if (d >= 0.7) {
                        respModel.difficultValue = "易";
                    } else if (d >= 0.4 && d < 0.7) {
                        respModel.difficultValue = "一般";
                    } else if (d >= 0.1 && d < 0.4) {
                        respModel.difficultValue = "难";
                    } else if (d < 0.1) {
                        respModel.difficultValue = "非常难";
                    }
                }
            } else {
                double avgScore = ScoreAlgorithm.scoreAvg(scoreAllLst);
                if (getSk > 0) {
                    if (avgScore >= examTotalScore * 0.9) {// 优秀：易
                        respModel.difficultValue = "易";
                    } else if (avgScore >= examTotalScore * 0.6 && avgScore < examTotalScore * 0.9) {// 良好、及格：一般
                        respModel.difficultValue = "一般";
                    } else if (avgScore >= examTotalScore * 0.45 && avgScore < examTotalScore * 0.6) {// 不及格：难
                        respModel.difficultValue = "难";
                    } else if (avgScore < examTotalScore * 0.45) {// 过差：非常难
                        respModel.difficultValue = "非常难";
                    }
                } else if (getSk == 0) {
                    if (avgScore >= examTotalScore * 0.6) {// 优秀、良好、及格：一般
                        respModel.difficultValue = "一般";
                    } else if (avgScore < examTotalScore * 0.6) {// 不及格、过差：难
                        respModel.difficultValue = "难";
                    }
                } else if (getSk < 0) {
                    if (avgScore >= examTotalScore * 0.8) {// 优秀、良好：一般
                        respModel.difficultValue = "一般";
                    } else if (avgScore >= examTotalScore * 0.6 && avgScore < examTotalScore * 0.8) {// 及格：难
                        respModel.difficultValue = "难";
                    } else if (avgScore < examTotalScore * 0.6) {// 不及格、过差：非常难
                        respModel.difficultValue = "非常难";
                    }
                }
            }

            // 分布分析
            String rankRemark = "";
            // 人数范围所需成绩集合（移除记录使用）
            List<Double> hsLst = new ArrayList<>();
            hsLst.addAll(scoreAllLst);
            // 迭代基数数字
            int baseNum = 0;
            switch (examTotalScore) {
            case 100:
                baseNum = 10;
                break;
            case 120:
                baseNum = 12;
                break;
            case 150:
                baseNum = 15;
                break;
            case 180:
                baseNum = 18;
                break;
            }
            Map<String, Integer> histogramMap = new HashMap<String, Integer>();
            // 循环取出范围
            for (int i = 0; i <= examTotalScore - baseNum; i += baseNum) {
                int count = 0;
                for (int j = 0; j < hsLst.size(); j++) {
                    if (i == 0) {
                        if (i <= hsLst.get(j) && hsLst.get(j) <= (i + baseNum)) {
                            count++;
                            hsLst.remove(j);
                        }
                    } else {
                        if (i < hsLst.get(j) && hsLst.get(j) <= (i + baseNum)) {
                            count++;
                            hsLst.remove(j);
                        }
                    }
                }
                histogramMap.put((i + baseNum) + "", count);
            }
            // 年级数据各个分数段
            List<Map.Entry<String, Integer>> histogramMapLst = new ArrayList<Map.Entry<String, Integer>>(
                    histogramMap.entrySet());
            // 人数排序
            histogramMapLst.sort((Map.Entry<String, Integer> h1, Map.Entry<String, Integer> h2) -> h2.getValue()
                    .compareTo(h1.getValue()));
            // 本班的柱状分布图
            ExamBaseAnalyse examAnalyse = examBaseAnalyseRepository.findByExam(exam);
            List<Map.Entry<String, Integer>> histogramBenMapLst = new ArrayList<Map.Entry<String, Integer>>(
                    examAnalyse.getHistogram().entrySet());
            // 本班人数排序
            histogramBenMapLst.sort((Map.Entry<String, Integer> h1, Map.Entry<String, Integer> h2) -> h2.getValue()
                    .compareTo(h1.getValue()));
            int histogramFlag = histogramBenMapLst.get(0).getKey().compareTo(histogramMapLst.get(0).getKey());
            int keyStr = Integer.parseInt(histogramBenMapLst.get(0).getKey());
            // 成绩分布
            if (histogramFlag > 0) {
                rankRemark += "如图，在本次考试中，当前班级成绩主要集中在" + (keyStr - 10) + "~" + keyStr + "分之间，高于年级成绩主要集中分段。";
            } else if (histogramFlag == 0) {
                rankRemark += "如图，在本次考试中，当前班级成绩主要集中在" + (keyStr - 10) + "~" + keyStr + "分之间，符合年级成绩主要集中分段。";
            } else if (histogramFlag < 0) {
                rankRemark += "如图，在本次考试中，当前班级成绩主要集中在" + (keyStr - 10) + "~" + keyStr + "分之间，低于年级成绩主要集中分段。";
            }

            double hiScoreBen = 0, hiScoreSum = 0, liScoreBen = 0, liScoreSum = 0;
            for (Entry<String, Integer> entry : histogramBenMapLst) {
                if (Integer.parseInt(entry.getKey()) >= (examTotalScore)) {
                    hiScoreBen += entry.getValue();
                }
                if (Integer.parseInt(entry.getKey()) <= (examTotalScore * 0.7)) {
                    liScoreBen += entry.getValue();
                }
            }
            for (Entry<String, Integer> entry : histogramMapLst) {
                if (Integer.parseInt(entry.getKey()) >= (examTotalScore)) {
                    hiScoreSum += entry.getValue();
                }
                if (Integer.parseInt(entry.getKey()) <= (examTotalScore * 0.7)) {
                    liScoreSum += entry.getValue();
                }
            }
            // 高分占比
            // double hiScoreAvg = hiScoreSum == 0d ? 0d : hiScoreBen /
            // hiScoreSum;
            // if (hiScoreAvg >= 0.6) {
            // rankRemark += "并且高分占年级比重较高。";
            // } else if (hiScoreAvg >= 0.2 && hiScoreAvg < 0.6) {
            // rankRemark += "但班级高分占年级比重一般。";
            // } else if (hiScoreAvg < 0.2) {
            // rankRemark += "但高分占比较低。";
            // }
            rankRemark += "并且高分占年级比重较高。";
            // 低分占比
            // double liScoreAvg = liScoreSum == 0d ? 0d : liScoreBen /
            // liScoreSum;
            // if (liScoreAvg >= 0.6) {
            // rankRemark += "同时低分占比过大，请加强当前班级基础巩固。";
            // } else if (liScoreAvg < 0.4) {
            // rankRemark += "同时低分成绩占比小于40%，希望老师进行针对性教学。";
            // }
            rankRemark += "同时低分占比过大，请加强当前班级基础巩固。";
            // 平均成绩
            List<ExamBaseAnalyse> examAnalyseLst = examBaseAnalyseRepository.findByExamIn(examLst);
            examAnalyseLst.sort((ExamBaseAnalyse h1, ExamBaseAnalyse h2) -> h2.getAverage().compareTo(h1.getAverage()));
            for (int i = 0; i < examAnalyseLst.size(); i++) {
                if (examAnalyseLst.get(i).getId().equals(examAnalyse.getId())) {
                    if (0 == i) {
                        rankRemark += "成绩平均分最高，请保持班级学习成绩";
                    } else {
                        List<String> classNameStr = new ArrayList<>();
                        for (int j = 0; j < i; j++) {
                            Exam exam2 = examRepository.findOne(examAnalyseLst.get(j).getExam().getId());
                            classNameStr.add(exam2.getClassName());
                        }
                        rankRemark += "成绩平均分低于" + StringUtils.join(classNameStr.toArray(), ",") + "，请注重教学法的调整。";
                    }
                    break;
                }
            }
            respModel.rankRemark = rankRemark;

            // 优良雷达图
            Map<Integer, Double> fineRank = new HashMap<Integer, Double>();
            for (int i = 0; i < 5; i++) {
                fineRank.put(i, 100d);
            }
            respModel.fineRank = fineRank;
        }
        return respModel;
    }

    /**
     * 获取Cell数据
     * 
     * @param cell
     * @return
     */
    private String getCellValueAsString(Cell cell) {
        String cellValue = "";
        if (cell == null) { return cellValue; }
        cell.setCellType(Cell.CELL_TYPE_STRING);
        switch (cell.getCellType()) {
        case Cell.CELL_TYPE_STRING:
            cellValue = cell.getRichStringCellValue().getString();
            // System.out.println(cell.getRichStringCellValue().getString());
            break;
        case Cell.CELL_TYPE_NUMERIC:
            if (DateUtil.isCellDateFormatted(cell)) {
                cellValue = new SimpleDateFormat("yyyy-MM-dd").format(cell.getDateCellValue());
                // System.out.println(cell.getDateCellValue());
            } else {
                cellValue = Double.valueOf(cell.getNumericCellValue()).toString();
                // System.out.println(cell.getNumericCellValue());
            }
            break;
        case Cell.CELL_TYPE_BOOLEAN:
            cellValue = Boolean.valueOf(cell.getBooleanCellValue()).toString();
            // System.out.println(cell.getBooleanCellValue());
            break;
        case Cell.CELL_TYPE_FORMULA:
            cellValue = cell.getCellFormula();
            // System.out.println(cell.getCellFormula());
            break;
        default:
            // System.out.println();
        }
        if (StringUtils.isNotBlank(cellValue)) {
            cellValue = cellValue.trim();
            cellValue = cellValue.replaceAll(" ", "");
        }
        return cellValue;
    }

    /**
     * 生成学生考试报告
     * 
     * @param exam
     * @throws ParseException
     */
    @Transactional
    public void StuReportCrt(Exam exam) throws ParseException {
        // 建立方差对象
        StandardDeviation stdDev = new StandardDeviation();
        // 学生基本信息
        Map<String, Stu> stuMap = new HashMap<>();
        for (Stu stu : exam.getStudents()) {
            stuMap.put(stu.student_id, stu);
        }
        // 考试小题
        List<ExamQues> quesLst = exam.getQuestions();
        // 本次考试基础分析
        ExamBaseAnalyse examBaseAnalyse = examBaseAnalyseRepository.findByExam(exam);
        // 本次考试全班平均分
        double avgScore = examBaseAnalyse.getAverage();
        // 学生考试详细成绩
        List<ExamStudent> examStuLst = examStudentRepository.findByExam(exam);
        // 当前班级的成绩
        double[] scoreAll = new double[examStuLst.size()];
        for (int i = 0; i < examStuLst.size(); i++) {
            scoreAll[i] = examStuLst.get(i).getStuTotalScore();
        }
        // 获取本次成绩的标准方差
        double benStdDev = stdDev.evaluate(scoreAll);

        // 本次考试覆盖的章节
        Integer bookContents = exam.getBookContents().size();
        // 本次考试覆盖的知识点
        List<String> bookContentLst = new ArrayList<String>();
        for (BookContent bc : exam.getBookContents()) {
            bookContentLst.add(bc.id);
        }
        List<Object> knowledgeIdList = yxyResBookContentsKnoledgesRepository.getKnowledge(bookContentLst);
        // 知识点覆盖数量
        Integer knowRemark = knowledgeIdList.size();

        List<String> stuLst = new ArrayList<String>();

        for (ExamStudent es : examStuLst) {
            // 学生成绩
            double stuTotalScore = es.getStuTotalScore();
            // 试卷满分
            double fullScore = exam.getTotalScore();
            String stuId = es.getStudentId();
            ExamStuReport stuReport = new ExamStuReport();
            stuReport.setId(exam.getId() + stuId);
            stuReport.setExamId(exam.getId());
            stuReport.setExamName(exam.getName());
            stuReport.setType(exam.getType());
            stuReport.setTeaId(exam.getTeacherId());
            stuReport.setTeaNick(exam.getTeacherNick());
            stuReport.setBookContents(bookContents);// 章节展示？
            stuReport.setKnowRemark(knowRemark);
            stuReport.setExamDate(DateUtils.formatStrDate4(exam.getExamDate()));
            stuReport.setSubject(exam.getSubjectName());
            stuReport.setStuId(stuId);
            stuReport.setStuNick(es.getStudentNick());
            stuReport.setGender(stuMap.get(stuId).gender);// 性别获取？
            stuReport.setStuTotalScore(stuTotalScore);

            // 历史成绩列表
            List<ExamStudent> historyESLst = new ArrayList<>();
            // 成绩评价（称号）
            String scoreType = "";
            historyESLst = examStudentRepository.findByStudentIdAndIdNotAndCreatedDateGreaterThanEqual(
                    es.getStudentId(), es.getId(), DateUtils.subtractMonth(new Date(), 6));
            if (0 == historyESLst.size()) {
                List<Double> historyScore = new ArrayList<>();
                // 是否降级
                boolean demotion = false;
                // 历史总分是否一致
                boolean consistent = true;// 标准差
                // 允许不及格次数
                int errorNum = 0;
                for (ExamStudent historyES : historyESLst) {
                    Exam historyExam = examRepository.findOne(historyES.getExam().getId());
                    // 历史考试满分
                    double hisstoryFullScore = historyExam.getTotalScore();
                    if (hisstoryFullScore == fullScore) {
                        historyScore.add(historyES.getStuTotalScore());
                        // ≥ 及格&& 历次总分 ≥ 及格线分数 - 5 && 历次考试不及格次数 ≤ 3
                        if (historyES.getStuTotalScore() < hisstoryFullScore * 0.6) {
                            if (errorNum > 3) {
                                demotion = false;
                                break;
                            }
                            if (historyES.getStuTotalScore() >= hisstoryFullScore * 0.6 - 5) {
                                errorNum++;
                            } else {
                                demotion = false;
                                break;
                            }
                        }
                    } else {
                        consistent = false;
                        if (stuTotalScore == fullScore) {
                            if (historyES.getStuTotalScore() < hisstoryFullScore * 0.9) {// ≥优秀
                                demotion = false;
                                break;
                            }
                        } else if (stuTotalScore >= fullScore * 0.9) {
                            if (historyES.getStuTotalScore() < hisstoryFullScore * 0.9) {// ≥优秀
                                demotion = false;
                                break;
                            }
                        } else if (stuTotalScore >= fullScore * 0.8 && stuTotalScore < fullScore * 0.9) {
                            if (historyES.getStuTotalScore() < hisstoryFullScore * 0.8) {// ≥良好
                                demotion = false;
                                break;
                            }
                        } else if (stuTotalScore >= fullScore * 0.6 && stuTotalScore < fullScore * 0.8) {
                            // ≥ 及格&& 历次总分 ≥ 及格线分数 - 5 && 历次考试不及格次数 ≤ 3
                            if (historyES.getStuTotalScore() < hisstoryFullScore * 0.6) {
                                if (errorNum > 3) {
                                    demotion = false;
                                    break;
                                }
                                if (historyES.getStuTotalScore() >= hisstoryFullScore * 0.6 - 5) {
                                    errorNum++;
                                } else {
                                    demotion = false;
                                    break;
                                }
                            }
                        }
                    }
                }
                double[] historyScoreArr = new double[historyScore.size()];
                for (int i = 0; i < historyScore.size(); i++) {
                    historyScoreArr[i] = historyScore.get(i);
                }
                stdDev = new StandardDeviation();
                // 样本方差
                double standardDev = stdDev.evaluate(historyScoreArr);

                if (stuTotalScore == fullScore) {
                    scoreType = "0";
                    if (consistent) {
                        switch ((int) fullScore) {
                        case 100:
                            if (standardDev > 7) {
                                scoreType = "1";
                            }
                            break;
                        case 120:
                            if (standardDev > 8) {
                                scoreType = "1";
                            }
                            break;
                        case 150:
                            if (standardDev > 10) {
                                scoreType = "1";
                            }
                            break;
                        case 180:
                            if (standardDev > 12) {
                                scoreType = "1";
                            }
                            break;
                        }
                    } else {
                        if (demotion) {
                            scoreType = "1";
                        }
                    }
                } else if (stuTotalScore >= fullScore * 0.9) {
                    scoreType = "1";
                    if (consistent) {
                        switch ((int) fullScore) {
                        case 100:
                            if (standardDev > 7) {
                                scoreType = "2";
                            }
                            break;
                        case 120:
                            if (standardDev > 8) {
                                scoreType = "2";
                            }
                            break;
                        case 150:
                            if (standardDev > 10) {
                                scoreType = "2";
                            }
                            break;
                        case 180:
                            if (standardDev > 12) {
                                scoreType = "2";
                            }
                            break;
                        }
                    } else {
                        if (demotion) {
                            scoreType = "2";
                        }
                    }
                } else if (stuTotalScore >= fullScore * 0.8 && stuTotalScore < fullScore * 0.9) {
                    scoreType = "2";
                    if (consistent) {
                        switch ((int) fullScore) {
                        case 100:
                            if (standardDev > 14) {
                                scoreType = "3";
                            }
                            break;
                        case 120:
                            if (standardDev > 16) {
                                scoreType = "3";
                            }
                            break;
                        case 150:
                            if (standardDev > 21) {
                                scoreType = "3";
                            }
                            break;
                        case 180:
                            if (standardDev > 25) {
                                scoreType = "3";
                            }
                            break;
                        }
                    } else {
                        if (demotion) {
                            scoreType = "3";
                        }
                    }
                } else if (stuTotalScore >= fullScore * 0.6 && stuTotalScore < fullScore * 0.8) {
                    scoreType = "3";
                    if (consistent) {
                        switch ((int) fullScore) {
                        case 100:
                            if (standardDev > 28 || demotion) {
                                scoreType = "5";
                            }
                            break;
                        case 120:
                            if (standardDev > 33 || demotion) {
                                scoreType = "5";
                            }
                            break;
                        case 150:
                            if (standardDev > 42 || demotion) {
                                scoreType = "5";
                            }
                            break;
                        case 180:
                            if (standardDev > 50 || demotion) {
                                scoreType = "5";
                            }
                            break;
                        }
                    } else {
                        if (demotion) {
                            scoreType = "5";
                        }
                    }
                } else if (stuTotalScore < fullScore * 0.6) {
                    scoreType = "5";
                }
            } else {
                if (stuTotalScore == fullScore) {
                    scoreType = "1";
                } else if (stuTotalScore >= fullScore * 0.9) {
                    scoreType = "2";
                } else if (stuTotalScore >= fullScore * 0.8 && stuTotalScore < fullScore * 0.9) {
                    scoreType = "3";
                } else if (stuTotalScore >= fullScore * 0.6 && stuTotalScore < fullScore * 0.8) {
                    scoreType = "4";
                } else if (stuTotalScore < fullScore * 0.6) {
                    scoreType = "5";
                }
            }
            stuReport.setScoreType(scoreType);

            // 题型评语
            String quesTypeRemark = null;
            if (quesLst.size() > 0) {
                int errorNum = 0;
                List<String> quesTypeStr = new ArrayList<>();
                for (StuQuesScore stuQuesScore : es.getStuQuesScores()) {
                    if (stuQuesScore.stu_score != (double) stuQuesScore.score) {
                        errorNum++;
                        if (stuQuesScore.stu_score == 0) {
                            quesTypeStr.add(quesLst.get(stuQuesScore.order_num - 1).sectionName + "_"
                                    + quesLst.get(stuQuesScore.order_num - 1).noName);
                        }
                    }
                }
                if (stuTotalScore == fullScore) {
                    quesTypeRemark = quesLst.size() + "道题分分钟搞定，就是有忽略题目难度的自信。";
                } else if (stuTotalScore >= fullScore * 0.9) {
                    quesTypeRemark = quesLst.size() + "道题统统不是事，偶尔扣几分，只是怕自己骄傲。";
                } else if (stuTotalScore >= fullScore * 0.8 && stuTotalScore < fullScore * 0.9) {
                    quesTypeRemark = quesLst.size() + "道题中，错误题目达到" + errorNum + "道。";
                    if (quesTypeStr.size() > 0) {
                        quesTypeRemark += "其中" + StringUtils.join(quesTypeStr.toArray(), ",") + "小题全线阵亡，请保持警惕！";
                    }
                } else if (stuTotalScore >= fullScore * 0.6 && stuTotalScore < fullScore * 0.8) {
                    quesTypeRemark = quesLst.size() + "道题中，错误题目达到" + errorNum + "道,适当调整学习状态有利于学习的进步！";
                } else if (stuTotalScore < fullScore * 0.6) {
                    quesTypeRemark = "爸爸妈妈！呼叫支援，我的试卷已阵亡。";
                }
            } else {
                quesTypeRemark = "未录入模板不显示当前内容。";
            }
            stuReport.setQuesTypeRemark(quesTypeRemark);

            // 班级平均分
            stuReport.setClassCompareAverageScore(avgScore);

            // 班级对比
            String classCompareRemark = "";
            switch (scoreType) {
            case "0":
                classCompareRemark = "稳定领先全班小伙伴，无敌是多么寂寞，班级平均成绩" + avgScore + "分";
                break;
            case "1":
                classCompareRemark = "爆发学习潜力，瞬间压制全班小伙伴，班级平均成绩" + avgScore + "分";
                if (es.getStuTotalScore() <= avgScore) {
                    classCompareRemark = "小伙伴们太给力，学习看来还需要努力，班级平均成绩" + avgScore + "分";
                }
                break;
            case "2":
                classCompareRemark = "考试心态爆炸，傲视班内小伙伴，班级平均成绩" + avgScore + "分";
                if (es.getStuTotalScore() <= avgScore) {
                    classCompareRemark = "隐匿于全班小伙伴中间，下次考试要加油啦，班级平均成绩" + avgScore + "分";
                }
                break;
            case "3":
                classCompareRemark = "考试逆势爆发，争取下回超过更多班级小伙伴，班级平均成绩" + avgScore + "分";
                if (es.getStuTotalScore() <= avgScore) {
                    classCompareRemark = "调整学习状态，下次要超越更多小伙伴，班级平均成绩" + avgScore + "分";
                }
                break;
            case "4":
                classCompareRemark = "稳稳超过班级考试平均线，班级平均成绩" + avgScore + "分";
                if (es.getStuTotalScore() < avgScore) {
                    classCompareRemark = "小伙伴为你加油，及格不是你的极限，班级平均成绩" + avgScore + "分";
                }
                break;
            case "5":
                classCompareRemark = "在小伙伴中，成绩屹立不倒，班级平均成绩" + avgScore + "分";
                if (es.getStuTotalScore() < avgScore) {
                    classCompareRemark = "小伙伴们功力大升，学习需要努力，班级平均成绩" + avgScore + "分";
                }
                break;
            }
            stuReport.setClassCompareRemark(classCompareRemark);

            // 对比上次考试
            ExamStudent lastExamStudent = examStudentRepository
                    .findTop1ByStudentIdAndExamNotOrderByCreatedDateDesc(stuId, exam.getId());
            if (null != lastExamStudent) {
                stuReport.setLastExamCompareFlag(1);
                // 上次考试信息
                Exam lastExam = examRepository.findById(lastExamStudent.getExam().getId());
                String lastExamCompare = "";
                if (lastExam.getTotalScore() == fullScore) {
                    switch (scoreType) {
                    case "0":
                        lastExamCompare = "虽然分数已达满分，不要骄傲继续保持";
                        if (stuTotalScore > lastExamStudent.getStuTotalScore()) {
                            stuReport.setLastCompareStatus(1);
                        } else {
                            if (stuTotalScore == lastExamStudent.getStuTotalScore()) {
                                stuReport.setLastCompareStatus(0);
                            } else {
                                stuReport.setLastCompareStatus(-1);
                            }
                        }
                        break;
                    case "1":
                        if (stuTotalScore > lastExamStudent.getStuTotalScore()) {
                            lastExamCompare = "每次考试进步一点点会收获更多，本次分数比上次分数上升"
                                    + (stuTotalScore - lastExamStudent.getStuTotalScore()) + "分";
                            stuReport.setLastCompareStatus(1);
                        } else {
                            if (stuTotalScore == lastExamStudent.getStuTotalScore()) {
                                lastExamCompare = "调整学习心态，请继续努力，本次分数于上次分数持平";
                                stuReport.setLastCompareStatus(0);
                            } else {
                                lastExamCompare = "调整学习方法，请继续努力，本次分数比上次分数下降"
                                        + Math.abs(stuTotalScore - lastExamStudent.getStuTotalScore()) + "分";
                                stuReport.setLastCompareStatus(-1);
                            }
                        }
                        break;
                    case "2":
                        if (stuTotalScore > lastExamStudent.getStuTotalScore()) {
                            lastExamCompare = "继续加油，保持努力势头将会得到更好成绩，本次分数比上次分数上升"
                                    + (stuTotalScore - lastExamStudent.getStuTotalScore()) + "分";
                            stuReport.setLastCompareStatus(1);
                        } else {
                            if (stuTotalScore == lastExamStudent.getStuTotalScore()) {
                                lastExamCompare = "调整学习心态，每一分都值得努力，本次分数于上次分数持平";
                                stuReport.setLastCompareStatus(0);
                            } else {
                                lastExamCompare = "调整学习心态，每一分都值得努力，本次分数比上次分数下降"
                                        + Math.abs(stuTotalScore - lastExamStudent.getStuTotalScore()) + "分";
                                stuReport.setLastCompareStatus(-1);
                            }
                        }
                        break;
                    default:
                        if (stuTotalScore > lastExamStudent.getStuTotalScore()) {
                            lastExamCompare = "继续努力，进步空间还很大，本次分数比上次分数上升"
                                    + (stuTotalScore - lastExamStudent.getStuTotalScore()) + "分";
                            stuReport.setLastCompareStatus(1);
                        } else {
                            if (stuTotalScore == lastExamStudent.getStuTotalScore()) {
                                lastExamCompare = "不要放弃，调整好心情下次再战，本次分数于上次分数持平";
                                stuReport.setLastCompareStatus(0);
                            } else {
                                lastExamCompare = "不要放弃，调整好心情下次再战，本次分数比上次分数下降"
                                        + Math.abs(stuTotalScore - lastExamStudent.getStuTotalScore()) + "分";
                                stuReport.setLastCompareStatus(-1);
                            }
                        }
                        break;
                    }
                } else {
                    // 学生考试详细成绩
                    List<ExamStudent> lastExamStuLst = examStudentRepository.findByExam(lastExam);
                    // 当前班级的成绩
                    double[] lastScoreAll = new double[lastExamStuLst.size()];
                    for (int i = 0; i < lastExamStuLst.size(); i++) {
                        lastScoreAll[i] = lastExamStuLst.get(i).getStuTotalScore();
                    }
                    // 获取本次成绩的标准方差
                    double lastStdDev = stdDev.evaluate(lastScoreAll);
                    // 上次考试基础分析
                    ExamBaseAnalyse lastBaseAnalyse = examBaseAnalyseRepository.findByExam(lastExam);
                    double benZScore = ScoreAlgorithm.standardScore(stuTotalScore, avgScore, benStdDev);
                    double lastZScore = ScoreAlgorithm.standardScore(lastExamStudent.getStuTotalScore(),
                            lastBaseAnalyse.getAverage(), lastStdDev);
                    switch (scoreType) {
                    case "0":
                        lastExamCompare = "虽然分数已达满分，不要骄傲继续保持";
                        if (benZScore > lastZScore) {
                            stuReport.setLastCompareStatus(1);
                        } else {
                            if (benZScore == lastZScore) {
                                stuReport.setLastCompareStatus(0);
                            } else {
                                stuReport.setLastCompareStatus(-1);
                            }
                        }
                        break;
                    case "1":
                        if (benZScore > lastZScore) {
                            lastExamCompare = "每次考试进步一点点会收获更多，平衡难度后，本次标准分比上次标准分上升";
                            stuReport.setLastCompareStatus(1);
                        } else {
                            if (benZScore == lastZScore) {
                                lastExamCompare = "调整学习方法，请继续努力，平衡难度后，本次标准分与上次标准分持平";
                                stuReport.setLastCompareStatus(0);
                            } else {
                                lastExamCompare = "调整学习方法，请继续努力，平衡难度后，本次标准分比上次标准分下降";
                                stuReport.setLastCompareStatus(-1);
                            }
                        }
                        break;
                    case "2":
                        if (benZScore > lastZScore) {
                            lastExamCompare = "继续加油，保持努力势头将会得到更好成绩，平衡难度后，本次标准分比上次标准分上升";
                            stuReport.setLastCompareStatus(1);
                        } else {
                            if (benZScore == lastZScore) {
                                lastExamCompare = "调整学习心态，每一分都值得努力，平衡难度后，本次标准分与上次标准分持平";
                                stuReport.setLastCompareStatus(0);
                            } else {
                                lastExamCompare = "调整学习心态，每一分都值得努力，平衡难度后，本次标准分比上次标准分下降";
                                stuReport.setLastCompareStatus(-1);
                            }
                        }
                        break;
                    default:
                        if (benZScore > lastZScore) {
                            lastExamCompare = "继续努力，进步空间还很大，平衡难度后，本次标准分比上次标准分上升";
                            stuReport.setLastCompareStatus(1);
                        } else {
                            if (benZScore == lastZScore) {
                                lastExamCompare = "不要放弃，调整好心情下次再战，平衡难度后，本次标准分与上次标准分持平";
                                stuReport.setLastCompareStatus(0);
                            } else {
                                lastExamCompare = "不要放弃，调整好心情下次再战，平衡难度后，本次标准分比上次标准分下降";
                                stuReport.setLastCompareStatus(-1);
                            }
                        }
                        break;
                    }
                }
                stuReport.setLastExamCompare(lastExamCompare);
            } else {
                stuReport.setLastExamCompareFlag(0);
            }

            // 回归算法
            double nextScore = 0d;
            RegressionLine line = new RegressionLine();
            if (0 != historyESLst.size()) {
                int count = 0;
                // 判断全部成绩是否相等
                boolean flag = false;
                for (ExamStudent examStudent : historyESLst) {
                    if (examStudent.getStuTotalScore() == stuTotalScore) {
                        count++;
                    }
                }
                if (count == historyESLst.size()) {
                    flag = true;
                }
                int i = 0;
                for (; i < historyESLst.size(); i++) {
                    double score = 0d;
                    if (historyESLst.get(i).getStuTotalScore() == 0) {
                        score = historyESLst.get(i).getStuTotalScore() + 0.1;
                    } else {
                        score = historyESLst.get(i).getStuTotalScore();
                    }
                    line.addDataPoint(new DataPoint(i + 1, (float) score));
                }
                if (flag) {
                    if (stuTotalScore == 0) {
                        line.addDataPoint(new DataPoint(i + 1, (float) (stuTotalScore + 0.2)));
                    } else {
                        line.addDataPoint(new DataPoint(i + 1, (float) (stuTotalScore + 0.1)));
                    }
                } else {
                    line.addDataPoint(new DataPoint(i + 1, (float) stuTotalScore));
                }
                nextScore = line.getA1() * (historyESLst.size() + 1) + line.getA0() - line.getR();
            } else {
                if (stuTotalScore == 0) {
                    line.addDataPoint(new DataPoint(1, (float) (stuTotalScore + 0.2)));
                } else {
                    line.addDataPoint(new DataPoint(1, (float) (stuTotalScore)));
                }
                line.addDataPoint(new DataPoint(2, (float) (stuTotalScore + 0.1)));
                nextScore = line.getA1() * 3 + line.getA0() - line.getR();
            }
            // 判断预测成绩是否与满分相符
            if (nextScore > fullScore) {
                nextScore = fullScore;
            } else if (nextScore < 0) {
                nextScore = 0;
            }
            // 预测范围
            double scorePoor = nextScore - stuTotalScore;
            if (scorePoor > 0) {
                stuReport.setNextExamRemark("您的成绩正在处于上升通道，虽然成绩好但不要懈怠学习哟。");
            } else {
                stuReport.setNextExamRemark("若不改变学习方法，调整好考试心态，下次将成下降趋势。");
            }
            Integer startScore = stuTotalScore - Math.ceil(Math.abs(scorePoor)) <= 0 ? 0
                    : (int) (stuTotalScore - Math.ceil(Math.abs(scorePoor)));
            Integer endScore = (int) (stuTotalScore + Math.ceil(Math.abs(scorePoor)) > fullScore ? fullScore
                    : stuTotalScore + Math.ceil(Math.abs(scorePoor)));
            stuReport.setNextExamScore(startScore + " ~ " + endScore);
            stuReport = examStuReportRepository.save(stuReport);

            stuLst.add(stuReport.getStuId());
        }
        if (stuLst.size() > 0) {
            ExamStuReportRunnable eReportRunnable = new ExamStuReportRunnable(stuLst, exam.getSchoolId(), yxyApiYxUrl,
                    restTemplate);
            eReportRunnable.start();
        }

    }

    /**
     * 正则判断string是否为double
     * 
     * @param str
     * @return
     */
    public static boolean isNumericDouble(String str) {
        Pattern patternInt = Pattern.compile("(^[+-]?([0-9]|([1-9][0-9]*)))");
        Pattern patternDouble = Pattern.compile("^[+-]?(([1-9]\\d*\\.?\\d+)|(0{1}\\.\\d+)|0{1})");// 判断是否为小数
        if (str == null) { return false; }
        return patternDouble.matcher(str).matches() || patternInt.matcher(str).matches();
    }
}
